<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <script>

      function debounce(fn, wait, immediate, refreshResolve) {
        var timer;

        var later = function(context, args) {
          timer = null;
          if (args) fn.apply(context, args);
        };

        return function() {
          var args = arguments;
          var context = this;

          if (timer) {
            clearTimeout(timer);
          }

          if (immediate) {
            var callNow = !timer;
            timer = setTimeout(later, wait);
            if (callNow) {
              fn.apply(context, args);
            } else if (refreshResolve && typeof args[0] === "function") {
              args[0]();
            }
          } else {
            timer = setTimeout(() => {
              later(context, args);
            }, wait);
          }
        };
      }

      //from _.js
      function throttle(func, wait, options) {
        var context, args, result;
        var timeout = null;
        // 上次执行时间点
        var previous = 0;
        if (!options) options = {};
        // 延迟执行函数
        var later = function() {
          // 若设定了开始边界不执行选项，上次执行时间始终为0
          previous = options.leading === false ? 0 : Date.now();
          timeout = null;
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        };
        return function() {
          var now = Date.now();
          // 首次执行时，如果设定了开始边界不执行选项，将上次执行时间设定为当前时间。
          if (!previous && options.leading === false) previous = now;
          // 延迟执行时间间隔
          var remaining = wait - (now - previous);
          context = this;
          args = arguments;
          var force = options.immediate;
          if (force) {
            options.immediate = false;
          }
          // 延迟时间间隔remaining小于等于0，表示上次执行至此所间隔时间已经超过一个时间窗口
          // remaining大于时间窗口wait，表示客户端系统时间被调整过
          if (remaining <= 0 || remaining > wait || force) {
            clearTimeout(timeout);
            timeout = null;
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
            //如果延迟执行不存在，且没有设定结尾边界不执行选项
          } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
          }
          return result;
        };
      }
    </script>
  </body>
</html>
